#pragma once

#include <iostream>
#include <queue>
#include <vector>
#include <pthread.h>
#include <functional>

#include"Thread.hpp"
#include"LockGuard.hpp"
#include"Log.hpp"
#include"Task.hpp"

using namespace std;

class ThreadData
{
public:
    ThreadData(const string& name)
        :threadname(name)
    {}

    ~ThreadData()
    {}

    string threadname;
};

static const int defaultnum = 5;

template<class T>
class ThreadPool
{
private:
    // ThreadPool()
    // {}
    
    ThreadPool(int thread_num = defaultnum)
        :_thread_num(thread_num)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);

        for(int i = 0; i < _thread_num; i++)
        {
            string threadname = "thread-";
            threadname += to_string(i + 1);

            ThreadData td(threadname);

            _threads.emplace_back(threadname, bind(&ThreadPool<T>::ThreadRun, this, placeholders::_1), td);
            log.LogMessages(Info, "%s is create...\n", threadname.c_str());
        }
    }

    ThreadPool(const ThreadPool<T>& td) = delete;
    ThreadPool<T>& operator=(const ThreadPool<T>& td) = delete;
    
public:
    static ThreadPool<T>* GetInstance()
    {
        if(instance == nullptr)
        {
            LockGuard lockguard(&sig_lock);
            if(instance == nullptr)
            {
                log.LogMessages(Info, "创建单例成功!");
                instance = new ThreadPool<T>;
            }
        }
        return instance;
    }

    bool start()/* 启动线程池 */
    {
        for(auto& thread : _threads)
        {
            thread.Start();
            log.LogMessages(Info, "%s is running ...\n", thread.ThreadName().c_str());
        }
        return true;
    }

    void ThreadWait(const ThreadData& td)
    {
        log.LogMessages(Debug, "no task, %s is sleeping...\n", td.threadname.c_str());
        pthread_cond_wait(&_cond, &_mutex);
    }

    void ThreadWakeup()
    {
        pthread_cond_signal(&_cond);
    }

    void checkSelf()
    {
        /* 水位线检查 */
    }

    void ThreadRun(ThreadData& td) /* 模拟pop消费者消费数据 */
    {
        while(true)
        {
            /* checkSelf(); */
            T t;
            {
                LockGuard lockguard(&_mutex);
                while(_q.empty())
                {
                    ThreadWait(td);
                    log.LogMessages(Debug, "thread %s is wakeup\n", td.threadname.c_str());
                }
                t = _q.front();
                _q.pop();
            }
            
            //Task t1;
           // log.LogMessages(Debug, "%s handler task %s done, result is : %s\n",
                          //td.threadname, t1.PrintTask().c_str(), t1.PrintResult().c_str());
        }
    }

    void Push(Task& in)
    {
        log.LogMessages(Debug, "other thread push a task, task is :%s \n", in.PrintTask().c_str());
        LockGuard lockguard(&_mutex);
        _q.push(in);
        ThreadWakeup();
    }

    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }

    void wait()
    {
        for(auto&  thread : _threads)
        {
            thread.Join();
        }
    }
private:
    queue<T> _q;
    vector<Thread<ThreadData>> _threads;
    int _thread_num;
    pthread_mutex_t _mutex;
    pthread_cond_t _cond;

    static ThreadPool<T>* instance;
    static pthread_mutex_t sig_lock;
};

/* 对static变量外部初始化 */
template <class T>
ThreadPool<T>* ThreadPool<T>::instance = nullptr;
template <class T>
pthread_mutex_t ThreadPool<T>::sig_lock = PTHREAD_MUTEX_INITIALIZER;